
// -----------------------------------------------------------------------------

#include "stdafx.h"
#include "Win32.String.h"
#include "Win32.Number.h"
#include "Win32.DateTime.h"

namespace Kif
{
namespace Win32
{

// -----------------------------------------------------------------------------

/// <summary>Set key value</summary>
/// <param name="line">line to parse/scan to get key and value</param>
/// <returns>true is returned if line was a key value...</returns>
bool ItemKeyValue::SetKeyValue(Kif::Win32::String &line)
{
   bool isKeyValue = true;
   TCHAR *buff, *topChar;
   buff = topChar = line.GetBuffer();

   // find ':' delimeter...
   while(*buff && (*buff != ':'))
      buff++;
   if (*buff == ':')
   {
      size_t kl = (size_t)(buff - topChar);
      Key.Copy(topChar,kl);
      while (*buff && (*(buff+1) == ' '))
         buff++;
      Value.Copy(buff+1,line.GetLength() - kl);
   }
   else
   {
      Dispose();
      isKeyValue = false;
   }
   return(isKeyValue);
}  // end of SetKeyValue

// -----------------------------------------------------------------------------

TCHAR *String::Concat(long number)
{
   String str;
   Kif::Win32::Number::ToString(str, number);
   return(Concat(str));
}  // end of Concat

// -----------------------------------------------------------------------------

/// <summary>Find a string within </summary>
/// <param name="sourceBuffer">source buffer in where to search for string
/// </param>
/// <param name="sourceLength">length of (source) buffer</param>
/// <param name="text">null terminated search string to find</param>
/// <param name="textLength">length of text</param>
/// <returns>a string pointer to the found source is returned if text is found
/// within the 'sourceBuffer', else NULL</returns>
TCHAR *String::FindString(
   TCHAR *sourceBuffer,size_t sourceLength, TCHAR *text,size_t textLength)
{
   bool found = false;
   size_t i,l = sourceLength;
   TCHAR *t,*x;
   for (i=0; i < sourceLength; i++,sourceBuffer++,l--)
   {
      if (l < textLength)
         break;
      t = text;
      x = sourceBuffer;
      while(*t && (*t == *x))
      {
         t++;
         x++;
      }
      if (*t == NULL)
      {
         found = true;
         break;
      }
   }
   return(found ? sourceBuffer : NULL);
}  // end of FindString

char *String::FindString(
   char *sourceBuffer,size_t sourceLength, char *text,size_t textLength)
{
   bool found = false;
   size_t i,l = sourceLength;
   char *t,*x;
   for (i=0; i < sourceLength; i++,sourceBuffer++,l--)
   {
      if (l < textLength)
         break;
      t = text;
      x = sourceBuffer;
      while(*t && (*t == *x))
      {
         t++;
         x++;
      }
      if (*t == NULL)
      {
         found = true;
         break;
      }
   }
   return(found ? sourceBuffer : NULL);
}  // end of FindString

TCHAR *String::FindBinaryItem(
   TCHAR *sourceBuffer,size_t sourceLength, TCHAR *text,size_t textLength)
{
   bool found = false;
   size_t l;
   TCHAR *buff  = sourceBuffer;
   TCHAR *tbuff, *base = nullptr;
   for (l=0; l < sourceLength; l++)
   {
      base  = buff;
      tbuff = text;
      while (*tbuff && (*buff == *tbuff))
      {
         buff++;
         tbuff++;
      }
      if (!(*tbuff))
      {
         found = true;
         break;
      }
      buff++;
   }
   return(found ? base : nullptr);
}  // end of FindBinaryString

// -----------------------------------------------------------------------------

/// <summary>get a substring of the given source string</summary>
/// <param name="start">start index (base 0)</param>
/// <param name="length">number of chars from substring</param>
/// <param name="sourceString">source string to get the substring from</param>
/// <returns>a string with the substring is returned</returns>
String *String::Substring(int start, int length,String *sourceString)
{
   // prepare output string and validate input string
   String *os = new String();
   if (sourceString == NULL)
      return(os);

   long l = (long)sourceString->GetLength();
   long x = (long)(start + length);
   if (x > l)
      l = l - start;
   else
      l = length;

   if (l <= 0)
      return(os);
   os->Copy(sourceString->GetBuffer()+start,l);

   return(os);
}  // end of Substring

// -----------------------------------------------------------------------------

/// <summary>copy a given ansi string value</summary>
/// <param name="buffer">buffer to copy</param>
/// <returns>the copied string is returned</returns>
TCHAR *String::Copy(char *buffer, size_t bufferSize)
{
   FreeBuffer();
   if (bufferSize <= 0)
      return(NULL);

   size_t l = bufferSize + 1;
   TCHAR *b = string.Alloc(l);
   if (b == NULL)
      return(NULL);

   return(Overwrite(buffer,bufferSize));
}  // end of Copy

/// <summary>copy a given string value</summary>
/// <param name="buffer">buffer to copy</param>
/// <param name="bufferSize">number of chars in buffer not including
/// null char</param>
/// <returns>the copied string is returned</returns>
TCHAR *String::Copy(TCHAR *buffer, size_t bufferSize)
{
   FreeBuffer();
   if (buffer == NULL)
      return(GetBuffer());

   size_t blen;
   if (bufferSize == 0)
      lastResult.HResult = StringCbLength(buffer,MaxLength,&blen);
   else
      blen = bufferSize * sizeof(TCHAR);

   if (lastResult.HResult == S_OK)
   {
      size_t l  = blen + sizeof(TCHAR);
      size_t sz = (l / sizeof(TCHAR));
      TCHAR *b  = string.Alloc(sz);
      if (b == NULL)
         return(NULL);

      lastResult.HResult = StringCbCopyN(b, l, buffer, blen);
      if (lastResult.HResult != S_OK)
      {
         string.Dispose();
         return(NULL);
      }
      length = sz - 1;
   }

   return(GetBuffer());
}  // end of Copy

// -----------------------------------------------------------------------------

/// <summary>concatenate given string to current buffer</summary>
/// <param name="buffer">buffer to concatenate</param>
/// <param name="bufferSize">number of chars in buffer</param>
/// <returns>the concatenated string is returned</returns>
TCHAR *String::Concat(TCHAR *buffer, size_t bufferSize)
{
   if (buffer == NULL)
      return(NULL);
   if (*buffer == NULL)
      return(NULL);

   // calculate the length of the string being copied
   size_t blen;
   if (bufferSize == 0)
      lastResult.HResult = StringCbLength(buffer,MaxLength,&blen);
   else
      blen = bufferSize * sizeof(TCHAR);

   if (lastResult.HResult == S_OK)
   {
      size_t bytesLength = (length * sizeof(TCHAR));
      size_t bLen = bytesLength + blen;
      size_t l = bLen + sizeof(TCHAR);
      TCHAR *b = (TCHAR*)Memory::alloc(l);
      if (b <= 0)
         return(NULL);

      *b = NULL;

      // make sure that we do copy the current buffer if there is something
      // to copy, else the concat operation was done on a non-existent buffer
      // and we only need to copy the given string buffer.
      if (bytesLength > 0)
      {
         lastResult.HResult =
            StringCbCopy(b, bytesLength + sizeof(TCHAR), string.Buffer);
         if (lastResult.HResult != S_OK)
         {
            Memory::free(b);
            return(NULL);
         }
      }

      lastResult.HResult = StringCbCat(b, l, buffer);
      if (lastResult.HResult != S_OK)
      {
         Memory::free(b);
         return(NULL);
      }

      string.SetDiposableBuffer(b,l);
      length = bLen / sizeof(TCHAR);

   }

   ValidateBuffer();

   return(GetBuffer());
}  // end of Concat

// -----------------------------------------------------------------------------

/// <summary>trim left and write spaces</summary>
TCHAR *String::Trim()
{
   TCHAR *fb = string.Buffer,*lb = string.Buffer + length - 1;

   // find first non-blank char
   while(*fb && (*fb == ' '))
      fb++;
   // find last non-blank char (going backwards)
   while((lb > fb) && (*lb == ' '))
      lb--;

   // this is a blank string
   if (*fb == NULL)
   {
      *string.Buffer = NULL;
      length = 0;
      return(string.Buffer);
   }

   // see if there is something wrong (psycho ckeck)
   if (fb > lb)
      return(string.Buffer);  // just ignore error

   // copy all chars to start of buffer and null terminate string
   if (*fb)
   {
      length = 0;
      TCHAR *pChr = string.Buffer;
      while (true)
      {
         *pChr = *fb;
         pChr++;
         fb++;
         length++;
         if (fb > lb)
            break;
      }
      *pChr = NULL;
   }

   return(string.Buffer);
}  // end of Trim

// -----------------------------------------------------------------------------

/// <summary>convert current TCHAR string into an ansi string</summary>
AnsiString *String::ToAnsiString(wchar_t *buffer)
{
   size_t length = getLength(buffer);
   char *as = (char*)Kif::Win32::Memory::alloc((length*sizeof(char))+1);
   if (as == NULL)
      return(NULL);

   AnsiString *ansiString = new AnsiString(as,length);
   wchar_t *ps = buffer;
   while(*ps)
   {
      *as = (char)*ps;
      as++;
      ps++;
   }
   *as = NULL;

   return(ansiString);
}  // end of ToAnsiString

/// <summary>convert current TCHAR string into an ansi string</summary>
AnsiString *String::ToAnsiString()
{
   char *as = (char*)Kif::Win32::Memory::alloc((length*sizeof(char))+1);
   if (as == NULL)
      return(NULL);

   AnsiString *ansiString = new AnsiString(as,length);
   TCHAR *ps = string.Buffer;
   while(*ps)
   {
      *as = (char)*ps;
      as++;
      ps++;
   }
   *as = NULL;

   return(ansiString);
}  // end of ToAnsiString

// -----------------------------------------------------------------------------

/// <summary>set all upper chars to lower chars</summary>
TCHAR *String::ToLower()
{
   if (string.Buffer == NULL)
      return(NULL);
   TCHAR *pl = string.Buffer;
   while (*pl)
   {
      if ((*pl >= 'A') && (*pl <= 'Z'))
         *pl = 'a' + (*pl - 'A');
      pl++;
   }
   return(string.Buffer);
}  // end of ToLower

/// <summary>set all lower chars to upper chars</summary>
TCHAR *String::ToUpper()
{
   if (string.Buffer == NULL)
      return(NULL);
   TCHAR *pl = string.Buffer;
   while (*pl)
   {
      if ((*pl >= 'a') && (*pl <= 'z'))
         *pl = 'A' + (*pl - 'a');
      pl++;
   }
   return(string.Buffer);
}  // end of ToUpper

TCHAR *String::ToUpper(TCHAR *string)
{
   if (string == NULL)
      return(String::GetEmptyString());

   TCHAR *pl = string;
   while (*pl)
   {
      if ((*pl >= 'a') && (*pl <= 'z'))
         *pl = 'A' + (*pl - 'a');
      pl++;
   }

   return(string);
}  // end of ToUpper

TCHAR *String::ToLower(TCHAR *string)
{
   if (string == NULL)
      return(String::GetEmptyString());

   TCHAR *pl = string;
   while (*pl)
   {
      if ((*pl >= 'A') && (*pl <= 'Z'))
         *pl = 'a' - (*pl - 'A');
      pl++;
   }

   return(string);
}  // end of ToUpper

// -----------------------------------------------------------------------------

TCHAR *String::GetUniqueId(String &uniqueId)
{
   static long count = 0;
   String cnt;
   Number::ToString(cnt,count);

   String *dtstr = DateTime::GetYmdHmsNameString();
   uniqueId.Copy(dtstr);
   uniqueId.Concat(cnt);
   count++;
   delete dtstr;

   return(uniqueId.GetBuffer());
}  // end of GetUniqueId

void String::GetPathAndFileName(
   TCHAR *filePath, String &path, String &fileName)
{
   path.Dispose();
   fileName.Dispose();

   TCHAR *lasts = NULL, *str = filePath;
   size_t lastsLen = 0, strLen = 0;
   while (*str)
   {
      if ((*str == '/') || (*str == '\\'))
      {
         lasts = str + 1;
         lastsLen = strLen + 1;
      }
      str++;
      strLen++;
   }

   size_t nameLen = strLen - lastsLen;
   if (lastsLen != 0)
   {
      path.Copy(filePath,lastsLen);
      if (nameLen != 0)
         fileName.Copy(lasts,nameLen);
      else
         fileName.Dispose();
   }
   else
   {
      path.Copy(filePath);
      fileName.Dispose();
   }
}  // end of GetUniqueId

/// <summary>To byte array</summary>
/// <param name="buffer">Buffer</param>
/// <param name="bufferLength">Buffer Length</param>
/// <returns>A byte array is returned. Buffer array must be disposed by
/// caller (using Memory::free).</returns>
BYTE *String::ToByteArray(TCHAR *buffer, size_t bufferLength)
{
   if ((buffer == NULL) || (bufferLength <= 0))
      return NULL;

   BYTE *byteArray = (BYTE *)Memory::alloc(sizeof(BYTE) * bufferLength);
   size_t i;
   for (i=0; i < bufferLength; i++)
      *(byteArray+i) = (BYTE)(*(buffer+i));
   return byteArray;
}  // end of ToByteArray

}  // end of Kif.Win32
}  // end of Kif

